# 创建ui界面，建立udp服务端，来接收cam的实时视频和控制小车。
# 已完成任务，esp32控制小车，pyQt的UI界面，UDP通信完成，UI为服务端，小车和CAM为客户端
# 未完成任务：TDOA定位 FOC电机（阉割掉） 多线程

import socket
import sys
import threading
import numpy as np
import io
from PIL import Image

import cv2
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import *
from PyQt5.QtNetwork import QUdpSocket, QHostAddress

from code_section import stopThreading

my_video_socket = None
UDP_CLIENT_IP_PORT = None
picture = None


# 创建多线程运行实时图像接受

class UDP_Thread(threading.Thread):
    def __init__(self, ip, port):
        super().__init__()
        self.img = None
        self.image = None
        self.video_socket = None
        self.video_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
        self.video_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.video_socket.bind((ip, port))
        self.video_socket.settimeout(10)
        global my_video_socket
        my_video_socket = self.video_socket
        # 设置运行的标志
        self.run_flag = True

    def run(self):
        global UDP_CLIENT_IP_PORT
        while self.run_flag:
            try:
                # 接收来自ESP32Cam的数据
                data, UDP_CLIENT_IP_PORT = self.video_socket.recvfrom(100000)
                print('接收ing')
                print(UDP_CLIENT_IP_PORT, " >>> ", data)
                bytes_stream = io.BytesIO(data)
                # print(bytes_stream)
                self.image = Image.open(bytes_stream)
                self.img = np.asarray(self.image)
                self.img = cv2.cvtColor(self.img, cv2.COLOR_RGB2BGR)  # ESP32采集的是RGB格式，要转换为BGR（opencv的格式）
                self.img = QtGui.QImage(self.img.data, self.img.shape[1], self.img.shape[0], QtGui.QImage.Format_BGR888)
                print(self.img)
                picture.setPixmap(QtGui.QPixmap.fromImage(self.img))
                picture.setScaledContents(True)
                # if cv2.waitKey(1) == ord("q"):
                #    break
            except Exception as ret:
                print("UdpThread error:", ret)

        # 结束后 关闭套接字
        self.video_socket.close()
        UDP_CLIENT_IP_PORT = None
        print("线程运行结束...")


def show_video():
    a = 1
    print(a)


class MainWindow(QWidget):
    # 信号槽机制：设置一个信号，用于触发接收区写入动作
    signal_write_msg = QtCore.pyqtSignal(str)

    def __init__(self):
        super().__init__()
        # ip列表
        # 获取本地电脑的ip地址列表
        self.udp_thread = None
        hostname, alias_list, ip_addr_list = socket.gethostbyname_ex(socket.gethostname())
        # print(ip_addr_list[-1])
        self.ip = ip_addr_list[-1]
        self.flag = False
        self.btn_open_udp_server = None
        self.client_cam = None
        self.client_car = None
        self.btn_cam = None
        self.btn_bind = None
        self.btn_show_vid = None
        self.lineEdit_ip_cam = None
        self.lineEdit_ip_car = None
        self.lineEdit_port_car = None
        self.lineEdit_port_cam = None
        self.btn_show_pic = None
        self.picture = None
        self.udp_r = None
        self.line_send = None
        self.label_1 = None
        self.btn_stop = None
        self.btn_Function = None
        self.btn_send = None
        self.btn_r = None
        self.btn_l = None
        self.udp_socket = None
        self.address = None
        self.sever_th = None
        self.link = False

        self.ui_eme()
        self.my_window()

        self.hearder_layout_1 = QHBoxLayout()  # 水平方向布局  ##################################1
        self.hearder_layout_2 = QHBoxLayout()
        self.hearder_layout_3 = QHBoxLayout()
        self.hearder_layout_4 = QHBoxLayout()
        self.hearder_layout_5 = QHBoxLayout()
        self.hearder_layout_6 = QHBoxLayout()
        self.hearder_layout_7 = QVBoxLayout()
        self.layout = QVBoxLayout()  # 垂直方向布局  ##################################1

        self.ui_layout()
        self.event_connect()

    def event_connect(self):
        self.btn_show_vid.clicked.connect(self.camera_open_close)
        self.btn_bind.clicked.connect(lambda: self.bind_client_ip_port(ip1=str(self.lineEdit_ip_car.text()),
                                                                       ip2=str(self.lineEdit_ip_cam.text()),
                                                                       port1=int(self.lineEdit_port_car.text()),
                                                                       port2=int(self.lineEdit_port_cam.text())))
        self.btn_l.clicked.connect(self.btn_l_event_add_click)
        self.btn_open_udp_server.clicked.connect(self.btn_open_event_add_click)
        self.signal_write_msg.connect(self.my_brow_show)
        self.btn_send.clicked.connect(
            lambda: self.udp_socket.sendto(self.line_send.text().encode('utf-8'), self.client_car))

    '''
    def click_get_ip(self):
        """
        pushbutton_get_ip控件点击触发的槽
        :return: None
        """
        # 获取本机ip
        self.lineEdit_ip.clear()
        my_addr = socket.gethostbyname(socket.gethostname())
        self.lineEdit_ip.setText(str(my_addr))
    '''

    def udp_server_create(self):
        self.link = True
        self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        print("建立套接字")
        try:
            port = 3030  # 固定本地端口为8080
            address = ('', port)
            self.udp_socket.bind(address)
            # self.udp_socket.sendto('light on'.encode('utf-8'), ('192.168.137.114', 5577))
            print("绑定本地")
        except Exception as ret:
            msg = '请检查端口号\n'
            self.signal_write_msg.emit(msg)
        else:
            self.sever_th = threading.Thread(target=self.udp_server_concurrency)
            self.sever_th.start()
            msg = 'UDP服务端正在监听端口:{}\n'.format(port)
            self.signal_write_msg.emit(msg)

    def udp_server_concurrency(self):
        """
        用于创建一个线程持续监听UDP通信
        :return:
        """
        while True:
            recv_msg, recv_addr = self.udp_socket.recvfrom(1024)
            print(recv_addr[0], recv_addr[1])
            msg = recv_msg.decode('utf-8')
            msg = '来自IP:{}端口:{}:\n{}\n'.format(recv_addr[0], recv_addr[1], msg)
            self.signal_write_msg.emit(msg)

    def my_window(self):
        # 窗体标题尺寸
        self.setWindowTitle("H妙妙屋")

        # 窗体的尺寸
        self.resize(800, 600)

        # 窗体的位置
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)

    def ui_eme(self):
        # 创建按钮等控件    *********************************
        self.btn_open_udp_server = QPushButton("open_server")
        self.btn_open_udp_server.setFixedSize(180, 100)
        self.btn_l = QPushButton("lift")
        self.btn_r = QPushButton("right")
        self.btn_send = QPushButton("send")
        self.btn_Function = QPushButton("fun_shift")
        self.btn_stop = QPushButton("stop")
        self.label_1 = QLabel("UDP接收数据")
        self.line_send = QLineEdit("发送的数据")
        self.udp_r = QTextBrowser()
        self.udp_r.setFixedSize(600, 150)
        self.picture = QLabel("图片显示")
        self.picture.setFixedSize(500, 400)
        global picture
        picture = self.picture
        self.btn_show_pic = QPushButton("show picture")
        self.btn_show_pic.setFixedSize(100, 100)
        self.lineEdit_port_car = QLineEdit("5577")  # 请输入端口号
        self.lineEdit_port_cam = QLineEdit("6060")  # 请输入端口号
        # self.btn_ip = QPushButton()
        self.lineEdit_ip_car = QLineEdit("请输入car客户端IP")
        self.lineEdit_ip_cam = QLineEdit("请输入cam客户端IP")  # 请输入目标IP
        self.btn_bind = QPushButton("绑定两个客户端信息")  # 连接两客户端
        # self.btn_cam = QPushButton("连接客户端cam")  # 连接cam客户端
        # self.btn_show_vid = QPushButton("关闭连接")
        self.btn_show_vid = QPushButton("show video")
        self.btn_show_vid.setFixedSize(100, 100)
        self.btn_show_vid.clicked.connect(self.camera_open_close)

    def ui_layout(self):
        self.hearder_layout_1.addWidget(self.btn_l)  #############3
        self.hearder_layout_1.addWidget(self.btn_r)

        self.hearder_layout_2.addWidget(self.btn_stop)  #############3
        self.hearder_layout_2.addWidget(self.btn_Function)  #############3

        self.hearder_layout_3.addWidget(self.label_1)  #############3
        self.hearder_layout_3.addWidget(self.line_send)  #############3
        self.hearder_layout_3.addWidget(self.btn_send)

        self.hearder_layout_4.addWidget(self.udp_r)  #############3
        self.hearder_layout_4.addWidget(self.btn_open_udp_server)  #############3

        self.hearder_layout_5.addWidget(self.picture)  #############3
        self.hearder_layout_7.addWidget(self.btn_show_pic)
        self.hearder_layout_7.addWidget(self.btn_show_vid)
        self.hearder_layout_5.addLayout(self.hearder_layout_7)

        self.hearder_layout_6.addWidget(self.lineEdit_ip_car)
        self.hearder_layout_6.addWidget(self.lineEdit_port_car)
        self.hearder_layout_6.addWidget(self.lineEdit_ip_cam)
        self.hearder_layout_6.addWidget(self.lineEdit_port_cam)
        self.hearder_layout_6.addWidget(self.btn_bind)

        self.layout.addLayout(self.hearder_layout_3)
        self.layout.addLayout(self.hearder_layout_4)
        self.layout.addLayout(self.hearder_layout_6)
        self.layout.addLayout(self.hearder_layout_5)
        # 加弹黄
        self.layout.addStretch()
        self.layout.addLayout(self.hearder_layout_1)
        self.layout.addLayout(self.hearder_layout_2)  #############2
        self.setLayout(self.layout)  ##########################1

    def my_udp_senddata(self, text, car_addre):
        self.udp_socket.sendto(text.encode('utf-8'), car_addre)
        msg = 'UDP客户端已发送\n'
        self.signal_write_msg.emit(msg)

    def bind_client_ip_port(self, ip1, ip2, port1, port2):
        self.client_car = (ip1, port1)
        self.client_cam = (ip2, port2)
        self.udp_r.append("信息绑定完成！！")

    def my_brow_show(self, msg):
        self.udp_r.append(msg)

    def btn_l_event_add_click(self):
        print('left')
        if self.link:  # 网络连接成功
            self.udp_socket.sendto((str("light on")).encode('utf-8'), self.client_car)

    def btn_open_event_add_click(self):
        if not self.flag:
            self.flag = True
            print("打开网络服务器")
            self.btn_open_udp_server.setFixedSize(160, 80)
            self.udp_server_create()

    def camera_open_close(self):
        """启动创建socket线程，用来接收显示数据"""
        if self.btn_show_vid.text() == "show video":
            ip = self.ip
            try:
                port = int(self.lineEdit_port_cam.text())
            except Exception as ret:
                print("出错了！！！！")
                return

            self.udp_thread = UDP_Thread(ip, port)  # 创建线程
            self.udp_thread.daemon = True
            self.udp_thread.start()
            self.btn_show_vid.setText("close video")
        else:
            # if self.udp_thread:
            #    self.udp_thread.run_flag = False  # 这里标记为False，当udp线程因为超时3秒后，自动判断，然后线程就退出了
            self.btn_show_vid.setText("show video")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
